/**
* Copyright (C) 2007 Pedro Miller Rabinovitch.
* http://www.opensource.org/licenses/mit-license.php
*
* Basically, feel free to use it however you want to.
* Please give me credit where appropriate.
*
* Pedro "Shade" Miller, gmail user: pedromr
* http://exodia.org
*
* @author Miller
*
* $Id: Vector3D.as 7 2007-12-13 10:07:21Z pedromr $
*/
package org.exodia.math {

	public class Vector3D {
		protected var _x:Number;
		protected var _y:Number;
		protected var _z:Number;
		
		protected var _length:Number;
		protected var _angle:Number;
		
		protected var _lengthReady:Boolean;
		protected var _angleReady:Boolean;
		
		public function get x() : Number {
			return _x;
		}
		
		public function get y() : Number {
			return _y;
		}
		
		public function get z() : Number {
			return _z;
		}
		
		public function set x(value:Number) : void {
			//trace( "Setting x to "+value );
			_x = value;
			//trace( "got _x "+_x );
			_lengthReady = false;
			_angleReady = false;
		}
		
		public function set y(value:Number) : void {
			_y = value;
			_lengthReady = false;
			_angleReady = false;
		}
		
		public function set z(value:Number) : void {
			_z = value;
			_lengthReady = false;
			_angleReady = false;
		}
		
		public function get length() : Number {
			if( !_lengthReady ) {
				_length = Math.sqrt( _x*_x + _y*_y + _z*_z );
				_lengthReady = true;
			}
			return _length;
		}
		
		public function set length(value:Number) : void {
			if( length == 0 ) {
				_x = 1;
				_y = _z = 0;
				_length = 1;
				_lengthReady = true;
			} else
				this.normalize();
			this.mul( value );
			_length = value;
			_lengthReady = true;
		}
		
		/**
		 * Returns the angle on the plane (X,Y)
		 */
		public function get angle2D() : Number {
			if( !_angleReady ) {
				_angle = Math.atan2( _y, _x );
				_angleReady = true;
			}
			return _angle;
		}
		
		public function set angle2D(angleRadians:Number) {
			var len:Number = length;
			_x = Math.cos( angleRadians ) * len;
			_y = Math.sin( angleRadians ) * len;
			_z = 0;
			_angle = angleRadians;
			_angleReady = true;
		}
		
		public function normalize() : Vector3D {
			if( length == 0 )
				return this;
			else
				return this.mul( 1/length );
		}
		
		public function mul( val:Number ) : Vector3D {
			_x *= val;
			_y *= val;
			_z *= val;
			_length *= val;
			return this;
		}
		
		public function add( other:Vector3D ) : Vector3D {
			_x += other._x;
			_y += other._y;
			_z += other._z;
			_lengthReady = false;
			_angleReady = false;
			return this;
		}
		
		public function sub( other:Vector3D ) : Vector3D {
			_x -= other._x;
			_y -= other._y;
			_z -= other._z;
			_lengthReady = false;
			_angleReady = false;
			return this;
		}
		
		public function clone() : Vector3D {
			return create().copyFrom( this );
		}
		
		public static function create( x:Number = 0, y:Number = 0, z:Number = 0 ) : Vector3D {
			return new Vector3D( x, y, z );
		}
		
		public function Vector3D( x:Number = 0, y:Number = 0, z:Number = 0 ) {
			_x = x;
			_y = y;
			_z = z;
		}
		
		public function copyFrom( vec : Vector3D ) : Vector3D {
			_x = vec.x;
			_y = vec.y;
			_z = vec.z;
			_lengthReady = vec._lengthReady;
			if( _lengthReady ) {
				_length = vec._length;
			}
			_angleReady= vec._angleReady;
			if( vec._angleReady ) {
				_angle = vec._angle;
			}
			return this;
		}
		
		public function toString() : String {
			return "< "+x+", "+y+", "+z+" > (length "+length+", "+angle2D*180/Math.PI+")";
		}
	}
	
}
